From c6b8bdfe3b47fe94999f5f85b518da09dd5aed9a Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Tue, 7 Jul 2009 14:38:59 +0100 Subject: [PATCH] x86: extend mmu_update hypercall to allow update of foreign pagetables. Signed-off-by: Jiang, Yunhong --- xen/arch/x86/mm.c | 53 ++++++++++++++++++++++++++++------------ xen/include/public/xen.h | 26 +++++++++++++------- 2 files changed, 55 insertions(+), 24 deletions(-) diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index b8d71f59cf..24117a6bc2 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -110,6 +110,7 @@ #include #include #include +#include #include #include @@ -2999,8 +3000,9 @@ int do_mmu_update( unsigned long gpfn, gmfn, mfn; struct page_info *page; int rc = 0, okay = 1, i = 0; - unsigned int cmd, done = 0; - struct domain *d = current->domain; + unsigned int cmd, done = 0, pt_dom; + struct domain *d = current->domain, *pt_owner = d; + struct vcpu *v = current; struct domain_mmap_cache mapcache; if ( unlikely(count & MMU_UPDATE_PREEMPTED) ) @@ -3018,7 +3020,29 @@ int do_mmu_update( goto out; } - if ( !set_foreigndom(foreigndom) ) + if ( (pt_dom = foreigndom >> 16) != 0 ) + { + /* Pagetables belong to a foreign domain (PFD). */ + if ( (pt_owner = rcu_lock_domain_by_id(pt_dom - 1)) == NULL ) + { + rc = -EINVAL; + goto out; + } + if ( pt_owner == d ) + rcu_unlock_domain(pt_owner); + if ( (v = pt_owner->vcpu ? pt_owner->vcpu[0] : NULL) == NULL ) + { + rc = -EINVAL; + goto out; + } + if ( !IS_PRIV_FOR(d, pt_owner) ) + { + rc = -ESRCH; + goto out; + } + } + + if ( !set_foreigndom((uint16_t)foreigndom) ) { rc = -ESRCH; goto out; @@ -3059,9 +3083,9 @@ int do_mmu_update( req.ptr -= cmd; gmfn = req.ptr >> PAGE_SHIFT; - mfn = gmfn_to_mfn(d, gmfn); + mfn = gmfn_to_mfn(pt_owner, gmfn); - if ( unlikely(!get_page_from_pagenr(mfn, d)) ) + if ( unlikely(!get_page_from_pagenr(mfn, pt_owner)) ) { MEM_LOG("Could not get page for normal update"); break; @@ -3080,24 +3104,21 @@ int do_mmu_update( { l1_pgentry_t l1e = l1e_from_intpte(req.val); okay = mod_l1_entry(va, l1e, mfn, - cmd == MMU_PT_UPDATE_PRESERVE_AD, - current); + cmd == MMU_PT_UPDATE_PRESERVE_AD, v); } break; case PGT_l2_page_table: { l2_pgentry_t l2e = l2e_from_intpte(req.val); okay = mod_l2_entry(va, l2e, mfn, - cmd == MMU_PT_UPDATE_PRESERVE_AD, - current); + cmd == MMU_PT_UPDATE_PRESERVE_AD, v); } break; case PGT_l3_page_table: { l3_pgentry_t l3e = l3e_from_intpte(req.val); rc = mod_l3_entry(va, l3e, mfn, - cmd == MMU_PT_UPDATE_PRESERVE_AD, 1, - current); + cmd == MMU_PT_UPDATE_PRESERVE_AD, 1, v); okay = !rc; } break; @@ -3106,8 +3127,7 @@ int do_mmu_update( { l4_pgentry_t l4e = l4e_from_intpte(req.val); rc = mod_l4_entry(va, l4e, mfn, - cmd == MMU_PT_UPDATE_PRESERVE_AD, 1, - current); + cmd == MMU_PT_UPDATE_PRESERVE_AD, 1, v); okay = !rc; } break; @@ -3115,7 +3135,7 @@ int do_mmu_update( case PGT_writable_page: perfc_incr(writable_mmu_updates); okay = paging_write_guest_entry( - current, va, req.val, _mfn(mfn)); + v, va, req.val, _mfn(mfn)); break; } page_unlock(page); @@ -3126,7 +3146,7 @@ int do_mmu_update( { perfc_incr(writable_mmu_updates); okay = paging_write_guest_entry( - current, va, req.val, _mfn(mfn)); + v, va, req.val, _mfn(mfn)); put_page_type(page); } @@ -3191,6 +3211,9 @@ int do_mmu_update( perfc_add(num_page_updates, i); out: + if ( pt_owner && (pt_owner != d) ) + rcu_unlock_domain(pt_owner); + /* Add incremental work we have done to the @done output parameter. */ if ( unlikely(!guest_handle_is_null(pdone)) ) { diff --git a/xen/include/public/xen.h b/xen/include/public/xen.h index af355ed678..1159055436 100644 --- a/xen/include/public/xen.h +++ b/xen/include/public/xen.h @@ -158,18 +158,26 @@ DEFINE_XEN_GUEST_HANDLE(xen_pfn_t); #define NR_VIRQS 24 /* - * MMU-UPDATE REQUESTS + * HYPERVISOR_mmu_update(reqs, count, pdone, foreigndom) * - * HYPERVISOR_mmu_update() accepts a list of (ptr, val) pairs. - * A foreigndom (FD) can be specified (or DOMID_SELF for none). - * Where the FD has some effect, it is described below. - * ptr[1:0] specifies the appropriate MMU_* command. + * @reqs is an array of mmu_update_t structures ((ptr, val) pairs). + * @count is the length of the above array. + * @pdone is an output parameter indicating number of completed operations + * @foreigndom[15:0]: FD, the expected owner of data pages referenced in this + * hypercall invocation. Can be DOMID_SELF. + * @foreigndom[31:16]: PFD, the expected owner of pagetable pages referenced + * in this hypercall invocation. The value of this field + * (x) encodes the PFD as follows: + * x == 0 => PFD == DOMID_SELF + * x != 0 => PFD == x - 1 * + * Sub-commands: ptr[1:0] specifies the appropriate MMU_* command. + * ------------- * ptr[1:0] == MMU_NORMAL_PT_UPDATE: - * Updates an entry in a page table. If updating an L1 table, and the new - * table entry is valid/present, the mapped frame must belong to the FD, if - * an FD has been specified. If attempting to map an I/O page then the - * caller assumes the privilege of the FD. + * Updates an entry in a page table belonging to PFD. If updating an L1 table, + * and the new table entry is valid/present, the mapped frame must belong to + * FD. If attempting to map an I/O page then the caller assumes the privilege + * of the FD. * FD == DOMID_IO: Permit /only/ I/O mappings, at the priv level of the caller. * FD == DOMID_XEN: Map restricted areas of Xen's heap space. * ptr[:2] -- Machine address of the page-table entry to modify. -- 2.30.2